﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Xml.Serialization;
using System.Text.RegularExpressions;
using System.IO;
using System.Xml;
using System.Reflection;

namespace URIDecoder
{
    [XmlRoot(Namespace = "http://twitter.com/Shyc2001/?Schema#URIDecoder")]
    public class EncodedURIScheme
    {
        [XmlAttribute("id")]
        public string Scheme { get; set; }
        public string EncodedUriRegex { get; set; }
        public string OriginalUriRegex { get; set; }
        public string Name { get; set; }
        public string EncodeMethod { get; set; }
        public string Decode(string encodedURIWithoutScheme)
        {
            string s = encodedURIWithoutScheme;
            Match m = System.Text.RegularExpressions.Regex.Match(s, EncodedUriRegex, RegexOptions.IgnoreCase);
            if (!m.Success) return null;
            s = m.Groups[1].Value;
            switch (EncodeMethod)
            {
                case "base64":
                    s = System.Text.Encoding.UTF8.GetString(Convert.FromBase64String(s));
                    break;
                case "uriescape":
                    s = Uri.UnescapeDataString(s);
                    break;
                case "plaintext":
                case "":
                    break;
                default:
                    string file = Path.Combine(new FileInfo(Environment.GetCommandLineArgs()[0]).DirectoryName, EncodeMethod + ".dll");
                    if (!File.Exists(file))
                    {
                        throw new ApplicationException(string.Format("未知的编码方式 \"{0}\"。请检查设置文件。", EncodeMethod));
                    }
                    else
                    {
                        Assembly asm = Assembly.LoadFile(file);
                        foreach (var t in asm.GetTypes())
                        {
                            if (t.IsSubclassOf(typeof(IURIDecoder)))
                            {
                                try
                                {
                                    s = ((IURIDecoder)Activator.CreateInstance(t)).Decode(s);
                                    goto found;
                                }
                                catch (Exception)
                                {

                                }
                            }
                        }
                        throw new ApplicationException(string.Format("解码扩展文件 \"{0}\" 中未找到实现 IURIDecoder 且具有拥有0个参数的构造函数的类。", file));
                    }
            }
            found:
            m = System.Text.RegularExpressions.Regex.Match(s, OriginalUriRegex, RegexOptions.IgnoreCase);
            if (!m.Success) return null;
            s = m.Groups[1].Value;
            return s;
        }

    }
    [XmlRoot(Namespace = "http://twitter.com/Shyc2001/?Schema#URIDecoder")]
    public class Downloader
    {
        public string FileName { get; set; }
        public string ArgumentsFormat { get; set; }
        [XmlAttribute("id")]
        public string Name { get; set; }
        public void StartDownload(string uristring)
        {
            string args = string.Format(ArgumentsFormat, uristring);
            System.Diagnostics.Process.Start(FileName, args);
        }
    }

    [XmlRoot("Config", Namespace = "http://twitter.com/Shyc2001/?Schema#URIDecoder")]
    public class ConfigFile
    {
        public List<EncodedURIScheme> Schemes { get; set; }
        public List<Downloader> Downloaders { get; set; }
        public string DefaultDownloader { get; set; }
        public const string ConfigFileName = "config.xml";
        public void ToFile()
        {
            string fn = Path.Combine(new FileInfo(Environment.GetCommandLineArgs()[0]).DirectoryName, ConfigFileName);
            using (XmlWriter xw = XmlWriter.Create(fn, new XmlWriterSettings() { Indent=true, IndentChars="  ", NewLineChars = Environment.NewLine }))
            {
                XmlSerializer xs = new XmlSerializerFactory().CreateSerializer(typeof(ConfigFile));
                xs.Serialize(xw, this);
            }
        }
        public static ConfigFile FromFile()
        {
            string fn = Path.Combine(new FileInfo(Environment.GetCommandLineArgs()[0]).DirectoryName, ConfigFileName);
            using (XmlReader xr = XmlReader.Create(fn))
            {
                XmlSerializer xs = new XmlSerializerFactory().CreateSerializer(typeof(ConfigFile));
                return xs.Deserialize(xr) as ConfigFile;
            }
        }
        public string AutoDecode(string uristring)
        {
            int delimiter = uristring.IndexOf(Uri.SchemeDelimiter);
            string scheme = uristring.Substring(0, delimiter).ToLower();
            string s = uristring.Substring(delimiter + Uri.SchemeDelimiter.Length);
            foreach (var item in Schemes)
                if (item.Scheme == scheme)
                    return item.Decode(s);
            throw new ApplicationException(string.Format("未找到协议 \"{0}\" 的解码规则。请检查设置文件。", scheme));
        }
        public void Download(string link)
        {
            if (string.IsNullOrEmpty(DefaultDownloader))
            {
                System.Diagnostics.Process.Start(link);
                return;
            }
            foreach (var item in Downloaders)
                if (item.Name == DefaultDownloader)
                {
                    item.StartDownload(link);
                    return;
                }
            throw new ApplicationException(string.Format("未找到下载程序 \"{0}\" 。请检查设置文件。", DefaultDownloader));
        }
    }
}
